﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Drawing.Graphics;
using System.Runtime.InteropServices;
using Tetris.Contral;
using Tetris.Data;
using System.Threading;

namespace Tetris.UI
{
    public enum EnumMoveDir
    {
        Down = 0,
        Left,
        Right,
        UP,
    }

    public partial class MainForm : Form
    {
        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();
        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        public MainForm()
        {
            InitializeComponent();
            _enableClose = false;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            _tom = new TetrisOnMap();
            MoveDownTimer.Interval = 60 * _level;
            InitMap();
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            
            if (keyData == Keys.Up || keyData == Keys.Down ||
                keyData == Keys.Left || keyData == Keys.Right)
                return false;
            else
                return base.ProcessDialogKey(keyData);
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void MainForm_Paint(object sender, PaintEventArgs e)
        {
            if (_enableClose)
            {
                DrawRectMouseMoveOn(e);
            }
            DrawCloseIcon(e);
            DrawGroup(e.Graphics);
            if (_bStart)
            {
                DrawTetrisOnMap(e.Graphics);
                DrawNextTetrisOnMap(e.Graphics);
            }
            DrawTetrisMap(e.Graphics);
        }

        /// <summary>
        /// 绘画关闭按键
        /// </summary>
        private void DrawCloseIcon(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Pen drawPen = new Pen(Color.Green, 2);
            Point x1 = new Point(this.Width - 15, 15);
            Point y1 = new Point(this.Width - 25, 25);
            Point x2 = new Point(this.Width - 25, 15);
            Point y2 = new Point(this.Width - 15, 25);
            g.DrawLine(drawPen, x1, y1);
            g.DrawLine(drawPen, x2, y2);     
        }

        /// <summary>
        /// 当鼠标移动到关闭键上时填充矩形框
        /// </summary>
        private void DrawRectMouseMoveOn(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Brush drawBrush = new SolidBrush(Color.Red);
            Rectangle rect = new Rectangle(this.Width - 30, 10, 20, 20);
            g.FillRectangle(drawBrush, rect);
        }
        
        /// <summary>
        /// 鼠标移动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_MouseMove(object sender, MouseEventArgs e)
        {
            if (MouseMoveOnClose(e.X, e.Y))
            {
                _enableClose = true;
                this.Invalidate();
            }
            else
            {
                _enableClose = false;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 判断鼠标是否在关闭键上
        /// </summary>
        /// <param name="mousePosX"></param>
        /// <param name="mousePosY"></param>
        /// <returns></returns>
        private bool MouseMoveOnClose(int mousePosX, int mousePosY)
        {
            bool ret = false;

            Point topLeft = new Point(this.Width - 30, 10);
            Point botRight = new Point(this.Width - 10, 30);
            if ((mousePosX > topLeft.X && mousePosX < botRight.X) && 
                (mousePosY > topLeft.Y && mousePosY < botRight.Y))
            {
                ret = true;
            }
            return ret;
        }
        
        /// <summary>
        /// 鼠标按键事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_MouseClick(object sender, MouseEventArgs e)
        {
            if (MouseMoveOnClose(e.X, e.Y))
            {
                Close();
            }
        }

        private void MainForm_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                if (!MouseMoveOnClose(e.X, e.Y))
                {
                    //常量  
                    int WM_SYSCOMMAND = 0x0112;

                    //窗体移动  
                    int SC_MOVE = 0xF010;
                    int HTCAPTION = 0x0002;

                    ReleaseCapture();
                    SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        
        private void MoveDownTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (_bStart)
                {
                    switch(_moveDir)
                    {
                        case EnumMoveDir.Down:
                            int result = _tom.MoveToDown();
                            if (result == 1)
                            {
                                _tom.TDInMap = _nextTd;
                                _nextTd = CreatTetri();
                            }
                            else if (result == 2)
                            {
                                _bStart = false;
                                MessageBox.Show("游戏结束");
                            }
                            _socre += _tom.GetScore();
                            tbScore.Text = _socre.ToString();
                            break;
                        //case EnumMoveDir.Left:
                        //    _tom.MoveToLeft();
                        //    break;
                        //case EnumMoveDir.Right:
                        //    _tom.MoveToRight();
                        //    break;
                        //case EnumMoveDir.UP:
                        //    _tom.ChangeType();
                        //    break;
                        default:
                            break;
                    }
                    this.Invalidate();
                    _moveDir = EnumMoveDir.Down;
                    MoveDownTimer.Interval = 500;
                }
            }
            catch (Exception ex)
            {
                _bStart = false;
                MessageBox.Show(ex.ToString());
            }
        }

        private void DrawTetrisOnMap(Graphics g)
        {
            try
            {
                Brush drawBrush = new SolidBrush(_tom.TDInMap.TetriColor);
                Pen drawPen = new Pen(Color.Black, 1);
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (_tom.TDInMap.Tetri.PosInMap.Row + i >= 0)
                        {
                            if (_tom.TDInMap.Tetri.Diamond[i, j] > 0)
                            {
                                Rectangle fillRect = new Rectangle(_tom.Map.MapX + _tom.Map.SizeOfDiamonds * (_tom.TDInMap.Tetri.PosInMap.Col + j), _tom.Map.MapY + _tom.Map.SizeOfDiamonds * (_tom.TDInMap.Tetri.PosInMap.Row + i), _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                                Rectangle rect = new Rectangle(_tom.Map.MapX + _tom.Map.SizeOfDiamonds * (_tom.TDInMap.Tetri.PosInMap.Col + j), _tom.Map.MapY + _tom.Map.SizeOfDiamonds * (_tom.TDInMap.Tetri.PosInMap.Row + i), _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                                g.FillRectangle(drawBrush, rect);
                                g.DrawRectangle(drawPen, rect);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void DrawTetrisMap(Graphics g)
        { 
            try
            {
                for (int row = 0; row < 20; row++)
                {
                    for (int col = 0; col < 10; col++)
                    {
                        if (_tom.Map.MapStatus[row, col] > 0)
                        {
                            Brush drawBrush = new SolidBrush(_dicColor[_tom.Map.MapStatus[row, col]]);
                            Pen drawPen = new Pen(Color.Black, 1);
                            Rectangle fillRect = new Rectangle(_tom.Map.MapX + _tom.Map.SizeOfDiamonds * col, _tom.Map.MapY + _tom.Map.SizeOfDiamonds * row, _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                            Rectangle rect = new Rectangle(_tom.Map.MapX + _tom.Map.SizeOfDiamonds * col, _tom.Map.MapY + _tom.Map.SizeOfDiamonds * row, _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                            g.FillRectangle(drawBrush, rect);
                            g.DrawRectangle(drawPen, rect);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void DrawNextTetrisOnMap(Graphics g)
        {
            try
            {
                Brush drawBrush = new SolidBrush(_nextTd.TetriColor);
                Pen drawPen = new Pen(Color.Black, 1);
                Pen drawFullPen = new Pen(Color.Black, 1);
                int x = _tom.Map.MapX + _tom.Map.MapWidth + 50-1;
                int y = _tom.Map.MapY-1;
                int width = _tom.Map.SizeOfDiamonds * 4 + 2;
                int height = _tom.Map.SizeOfDiamonds * 4 + 2;
                Rectangle fullRect = new Rectangle(x, y, width, height);
                g.DrawRectangle(drawPen, fullRect);
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (_nextTd.Tetri.Diamond[i, j] > 0)
                        {
                            Rectangle fillRect = new Rectangle(x + _tom.Map.SizeOfDiamonds *  j, _tom.Map.MapY + _tom.Map.SizeOfDiamonds *  i, _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                            Rectangle rect = new Rectangle(x + _tom.Map.SizeOfDiamonds * j, _tom.Map.MapY + _tom.Map.SizeOfDiamonds * i, _tom.Map.SizeOfDiamonds, _tom.Map.SizeOfDiamonds);
                            g.FillRectangle(drawBrush, rect);
                            g.DrawRectangle(drawPen, fillRect);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        
        private void BtnStart_Click(object sender, EventArgs e)
        {
            _bStart = true;
            CleanMap();
            _tom.TDInMap = CreatTetri();
            _nextTd = CreatTetri();
        }

        private TetrisData CreatTetri()
        {
            TetrisData tetrisData = null;
            Random ra = new Random();
            int tetrisType = ra.Next(0, 7);
            switch (tetrisType)
            {
                case (int)TetrisType.I:
                    TetrisI ti = new TetrisI();
                    tetrisData = ti;
                    break;
                case (int)TetrisType.J:
                    TetrisJ tj = new TetrisJ();
                    tetrisData = tj;
                    break;
                case (int)TetrisType.L:
                    TetrisL tl = new TetrisL();
                    tetrisData = tl;
                    break;
                case (int)TetrisType.O:
                    TetrisO to = new TetrisO();
                    tetrisData = to;
                    break;
                case (int)TetrisType.S:
                    TetrisS ts = new TetrisS();
                    tetrisData = ts;
                    break;
                case (int)TetrisType.Z:
                    TetrisZ tz = new TetrisZ();
                    tetrisData = tz;
                    break;
                case (int)TetrisType.T:
                    TetrisT tt = new TetrisT();
                    tetrisData = tt;
                    break;
            }
            return tetrisData;
        }

        private void DrawGroup(Graphics g)
        {
            Pen drawBrush = new Pen(Color.Black, 2);
            Rectangle rect = new Rectangle(_tom.Map.MapX, _tom.Map.MapY, _tom.Map.MapWidth, _tom.Map.MapHeight);
            g.DrawRectangle(drawBrush, rect);
        }

        private void CleanMap()
        {
            _tom.Map.ClearMap();
        }

        private void InitMap()
        {
            _tom.Map.SizeOfDiamonds = 25;
            if ((_tom.Map.SizeOfDiamonds * _tom.Map.MapCols > this.Width / 2) || (_tom.Map.SizeOfDiamonds * _tom.Map.MapRows > this.Height - 40))
            {
                _tom.Map.SizeOfDiamonds -= ((_tom.Map.SizeOfDiamonds * _tom.Map.MapCols - this.Width / 2) / _tom.Map.MapCols);
            }
            int x = 20;
            int y = this.Height - 20 - _tom.Map.SizeOfDiamonds * _tom.Map.MapRows;
            int width = _tom.Map.SizeOfDiamonds * _tom.Map.MapCols;
            int height = _tom.Map.SizeOfDiamonds * _tom.Map.MapRows;
            _tom.Map.MapX = x;
            _tom.Map.MapY = y;
            _tom.Map.MapWidth = width;
            _tom.Map.MapHeight = height;
            _dicColor = new Dictionary<int, Color>();
            _dicColor.Add(1, Color.Red);
            _dicColor.Add(2, Color.Blue);
            _dicColor.Add(3,Color.Green);
            _dicColor.Add(4, Color.Gold);
            _dicColor.Add(5, Color.Orange);
            _dicColor.Add(6, Color.Pink);
            _dicColor.Add(7, Color.Yellow);
        }

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    //_moveDir = EnumMoveDir.Left;
                    //MoveDownTimer.Interval = 100;
                    _tom.MoveToLeft();
                    Refresh();
                    break;
                case Keys.Right:
                    //_moveDir = EnumMoveDir.Right;
                    //MoveDownTimer.Interval = 100;
                    _tom.MoveToRight();
                    Refresh();
                    break;
                case Keys.Up:
                    //_moveDir = EnumMoveDir.UP;
                    //MoveDownTimer.Interval = 100;
                    _tom.ChangeType();
                   // Refresh();
                    break;
                case Keys.Down:
                    _moveDir = EnumMoveDir.Down;
                    MoveDownTimer.Interval = 100;
                    break;
                default:
                    break;
            }
        }

        //private void StartDown()
        //{
        //    _t = new Thread(_tom.Move);
        //    _t.Start();
        //}

        private bool _bStart = false;
        //private TetrisData _td;
        private TetrisOnMap _tom;
        private bool _enableClose;
        private int _level = 10;
        private Dictionary<int, Color> _dicColor;
        private int _socre = 0;
        private TetrisData _nextTd;
        private EnumMoveDir _moveDir;
    }
}
